#include <init/IRQ.h>
#include <init/IDT.h>
#include <init/PIC.h>

/* These are own ISRs that point to our special IRQ handler
 *  instead of the regular 'fault_handler' function */
extern void irq0();
extern void irq1();
extern void irq2();
extern void irq3();
extern void irq4();
extern void irq5();
extern void irq6();
extern void irq7();
extern void irq8();
extern void irq9();
extern void irq10();
extern void irq11();
extern void irq12();
extern void irq13();
extern void irq14();
extern void irq15();

/* Array is function pointers to handle custom IRQ handlers for a given IRQ */
void *irq_routines[16] = { 0 };
/*
{
  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0
};
*/

/* This installs a custom IRQ handler for the given IRQ */
void irq_install_handler(_s32 irq, void (*handler)(struct registers *r))
{
  irq_routines[irq] = handler;
}

/* This clears the handler for a given IRQ */
void irq_uninstall_handler(_s32 irq)
{
  irq_routines[irq] = 0;
}

/* Remap the interrupt controllers, and install appropriate ISRs 
 * to the correct entries in the IDT. */
void irq_install()
{
  /*  Remap IRQs */
  pic_remap(0x20, 0x28);

  idt_set_gate(32, (unsigned)irq0, 0x08, 0x8E);
  idt_set_gate(33, (unsigned)irq1, 0x08, 0x8E);
  idt_set_gate(34, (unsigned)irq2, 0x08, 0x8E);
  idt_set_gate(35, (unsigned)irq3, 0x08, 0x8E);
  idt_set_gate(36, (unsigned)irq4, 0x08, 0x8E);
  idt_set_gate(37, (unsigned)irq5, 0x08, 0x8E);
  idt_set_gate(38, (unsigned)irq6, 0x08, 0x8E);
  idt_set_gate(39, (unsigned)irq7, 0x08, 0x8E);
  idt_set_gate(40, (unsigned)irq8, 0x08, 0x8E);
  idt_set_gate(41, (unsigned)irq9, 0x08, 0x8E);
  idt_set_gate(42, (unsigned)irq10, 0x08, 0x8E);
  idt_set_gate(43, (unsigned)irq11, 0x08, 0x8E);
  idt_set_gate(44, (unsigned)irq12, 0x08, 0x8E);
  idt_set_gate(45, (unsigned)irq13, 0x08, 0x8E);
  idt_set_gate(46, (unsigned)irq14, 0x08, 0x8E);
  idt_set_gate(47, (unsigned)irq15, 0x08, 0x8E);
}

void irq_handler(struct registers *r)
{
  /* Declare blank function pointer */
  void (*handler)(struct registers *r);

  /* Find out if there is a custom handler to run for this
   * IRQ and run it */
  handler = irq_routines[r->int_no - 32];
  if (handler)
  {
    handler(r);
  }

  pic_sendEOI(r->int_no, 40);
}
